﻿using Microsoft.SharePoint;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using System.Text;

namespace WindStyle.SPEntity.Converters
{
    public class SPFieldLookupValueConverter : IValueConverter
    {
        public virtual object ToFieldValue(object value, Type targetType, ConversionContext context)
        {
            var type = value.GetType();
            var lookupValue = this.GetLookupValue(value, type, context.Attribute);

            if (targetType == typeof(SPFieldLookupValue))
                return lookupValue;
            else if (targetType == typeof(SPFieldUserValue))
                return new SPFieldUserValue(context.Item.Web,
                            lookupValue.LookupId,
                            lookupValue.LookupValue);
            return null;
        }

        public virtual object ToPropertyValue(object value, Type targetType, ConversionContext context)
        {
            var fieldValue = value as SPFieldLookupValue;
            if (fieldValue == null && !string.IsNullOrEmpty(value as string))
                fieldValue = new SPFieldLookupValue(value as string);
            if (fieldValue != null)
            {
                if (context.Attribute is Attributes.LookupFieldAttribute)
                {
                    var lookupAttribute = context.Attribute as Attributes.LookupFieldAttribute;
                    if (lookupAttribute.ValuePart == Attributes.LookupValue.Id)
                    {
                        return Convert.ChangeType(fieldValue.LookupId, targetType);
                    }
                    else if (lookupAttribute.ValuePart == Attributes.LookupValue.Value)
                    {
                        return Convert.ChangeType(fieldValue.LookupValue, targetType);
                    }
                    else
                    {
                        var result = Activator.CreateInstance(targetType);
                        this.WriteEntity(result, targetType, fieldValue, lookupAttribute);
                        return result;
                    }
                }
                else if (targetType == typeof(SPUser))
                {
                    var userFieldValue = new SPFieldUserValue(context.Item.Web, fieldValue.ToString());
                    return userFieldValue.User;
                }
            }
            return null;
        }

        protected void WriteEntity(object entity, Type type, SPFieldLookupValue value, Attributes.LookupFieldAttribute attribute)
        {
            try
            {
                var lookupIdProperty = type.GetProperty(attribute.IdProperty);
                var lookupId = System.Convert.ChangeType(value.LookupId, lookupIdProperty.PropertyType);
                lookupIdProperty.SetValue(entity, lookupId, null);
            }
            catch (Exception e)
            {
                throw new ArgumentException(string.Format("Convert Lookup Id failed, cannot find property [{0}] or the value [{1}] cannot be converted to the type of that property.",
                    attribute.IdProperty,
                    value.LookupId), e);
            }

            try
            {
                var lookupValueProperty = type.GetProperty(attribute.ValueProperty);
                var lookupValue = System.Convert.ChangeType(value.LookupValue, lookupValueProperty.PropertyType);
                lookupValueProperty.SetValue(entity, lookupValue, null);
            }
            catch (Exception e)
            {
                throw new ArgumentException(string.Format("Convert Lookup Value failed, cannot find property [{0}] or the value [{1}] cannot be converted to the type of that property.",
                    attribute.ValueProperty,
                    value.LookupValue), e);
            }
        }

        protected SPFieldLookupValue GetLookupValue(object value, Type type, Attributes.FieldAttribute attribute)
        {
            if (attribute != null)
            {
                if (value is SPUser)
                {
                    var user = value as SPUser;
                    return new SPFieldLookupValue(user.ID, user.Name);
                }
                else
                {
                    var lookupAttribute = attribute as Attributes.LookupFieldAttribute;
                    int lookupId;
                    try
                    {
                        lookupId = Convert.ToInt32(type.GetProperty(lookupAttribute.IdProperty).GetValue(value, null));
                    }
                    catch (Exception e)
                    {
                        throw new ArgumentException(string.Format("Convert Lookup Id failed, cannot find property [{0}] or the value of that property cannot be converted to Int32.",
                            lookupAttribute.IdProperty),
                            e);
                    }

                    string lookupValue = string.Empty;
                    try
                    {
                        var result = type.GetProperty(lookupAttribute.ValueProperty).GetValue(value, null);
                        if (result != null)
                            lookupValue = result.ToString();
                    }
                    catch (Exception e)
                    {
                        throw new ArgumentException(string.Format("Convert Lookup Value failed, cannot find property [{0}].",
                            lookupAttribute.IdProperty),
                            e);
                    }
                    return new SPFieldLookupValue(lookupId, lookupValue);
                }
            }
            return null;
        }
    }
}
